//
// Created by momolove on 22-12-2.
//

#ifndef UNIX_EXP_CFSERVER_H
#define UNIX_EXP_CFSERVER_H

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <fcntl.h>

#include "common.h"

#define send_error_message(client_fd, format, ...) dprintf(client_fd, "e" format "\n", ##__VA_ARGS__)

enum EXIT_STATUS {
    ERR_FSERVER_DIRECTORY_MISSING = 1,
    ERR_FSERVER_ARGUMENT_INVALID = 2,
    ERR_FSERVER_ARGUMENT_MISSING = 3,
    ERR_FSERVER_PORT_INVALID = 4,
    ERR_FSERVER_DIRECTORY_RESPECIFIED = 11,
    ERR_FSERVER_NOT_A_DIRECTORY = 12,
    ERR_FSERVER_ACCESS_DENINED = 13,
    ERR_FSERVER_INTERNAL_ERROR = 101,
};

const struct option long_options_server[] = {
        {"listen", required_argument, NULL, 'l'},
        {"hidden", no_argument, NULL, 'H'},
        {"port", required_argument, NULL, 'p'},
        {"help", no_argument, NULL, 'h'},
        {0, 0, 0, 0}
};
const char *short_options_server = "-l:Hp:h";

struct fserver_arguments_t {
    BOOL hidden;
    char *hostname;
    char *dirname;
    size_t dirname_len;
    int port;
} options = { FALSE, "localhost", "", 0, 12345 };

#define BUF_SIZE 256        // send buffer
#define THREADS_COUNT 3
#define MAX_REC_DEPTH 4

#define MAX_INDENT ((MAX_REC_DEPTH + 1) * 2)

int socket_fd, connected_fd;
char indent[MAX_INDENT + 1];

int main(int argc, char* argv[]);

void init();

/**
 * Print the help message in stderr and exit with -1.
 * @param arg0 (char*) a string to be displayed as the program name, normally it should be argv[0].
 */
void print_help_and_exit(const char *arg0);

/**
 * Parse arguments provided in command line, starting with argv[1].
 * @param argc (int) number of arguments, should be argc of main
 * @param argv (char**) array of arguments, should be argv of main
 */
void parse_args(int argc, char* argv[]);

int list_files(int out_fd, char **path_ptr, size_t pathlen, int layer, int depth);

void send_file(int client_fd, char *filename);

int start_server(int qlen);

void do_fserver();

void *handle_client_session(void *data);

int handle_list_files(int out_fd);

void handle_download_file(int client_fd);

#endif // UNIX_EXP_CFSERVER_H
